package com.example.demo.config;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.example.demo.channel.RedisMessagePublisher;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @PackageName: com.example.demo.config
 * @ClassName: WebSocketServer
 * @Description:
 * @Author: czl
 * @Date: 2025/7/27 14:26
 */
@Component
@ServerEndpoint(value = "/webSocket/{userId}")
public class WebSocketServer {

    private static final Logger log = LoggerFactory.getLogger(WebSocketServer.class);

    public static final String serverPort = "8087";
    private final String USER_SESSION_ID_MAP = "userSessionIdMap";
    private final String SESSION_USER_ID_MAP = "sessionUserIdMap";
    private final String WEBSOCKET_SESSION_KEY = "customSessionId";
    public static final String PUB_SUB_KEY = "common_pub_sub";

    public static Map<String, Session> clientMap = new ConcurrentHashMap<>();

    private static RedisCache redisCache;
    private static RedisMessagePublisher messagePublisher;

    @Autowired
    public void setRedisCache(RedisCache redisCache) {
        WebSocketServer.redisCache = redisCache;
    }

    @Autowired
    public void setMessagePublisher(RedisMessagePublisher messagePublisher) {
        WebSocketServer.messagePublisher = messagePublisher;
    }

    /**
     * 客户端与服务端连接成功
     *
     * @param session
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("userId") String userId) throws IOException {
        String sessionId = UUID.randomUUID().toString();
        session.getUserProperties().put(WEBSOCKET_SESSION_KEY, sessionId);
        log.info("ws -> 客户端与服务端连接成功 userId:{} sessionID: {},port:{}", userId, session.getId(), serverPort);
        redisCache.setCacheMapValue(USER_SESSION_ID_MAP, String.valueOf(userId), sessionId);
        redisCache.setCacheMapValue(SESSION_USER_ID_MAP, sessionId, String.valueOf(userId));
        clientMap.put(sessionId, session);
        String msg = String.format("ws -> 客户端与服务端连接成功 userid:%s sessionID: %s,port:%s", userId, session.getId(), serverPort);
        session.getBasicRemote().sendText(msg);
    }

    /**
     * 客户端与服务端连接关闭
     *
     * @param session
     */
    @OnClose
    public void onClose(Session session, @PathParam("userId") String userId) {
        String sessionId = (String) session.getUserProperties().get(WEBSOCKET_SESSION_KEY);
        log.info("ws -> 客户端与服务端连接关闭 sessionID: {},port:{}", sessionId, serverPort);
        redisCache.deleteCacheMapValue(USER_SESSION_ID_MAP, userId);
        redisCache.deleteCacheMapValue(SESSION_USER_ID_MAP, sessionId);
        clientMap.remove(sessionId, session);
    }

    /**
     * 客户端与服务端连接异常
     *
     * @param error
     * @param session
     */
    @OnError
    public void onError(Throwable error, Session session) {
        log.error("ws -> 客户端与服务端连接异常 sessionID: {},port:{}", session.getId(), serverPort, error);
    }

    /**
     * 客户端向服务端发送消息
     *
     * @param message 传递信息
     * @param session 当前会话
     */
    @OnMessage
    public void onMsg(String message, Session session) throws IOException {
        JSONObject jsonObject = JSON.parseObject(message);
        String userId = jsonObject.getString("to");
        String msgInfo = jsonObject.getString("msg");
        String sessionId = redisCache.getCacheMapValue(USER_SESSION_ID_MAP, userId);
        jsonObject.put("sessionId", sessionId);
        if (null != sessionId && clientMap.get(sessionId) != null) {
            session.getBasicRemote().sendText(msgInfo);
            log.info("ws -> 客户端向服务端发送消息 message:{}, sessionID: {},port:{}", message, session.getId(), serverPort);
        } else {
            messagePublisher.publish(PUB_SUB_KEY, JSON.toJSONString(jsonObject));
        }
    }
}
